/*
 * CharacterSprite.java
 *
 * Created on January 20, 2008, 9:13 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package wisp.game;
//JFC
import com.golden.gamedev.object.sprite.AdvanceSprite;
import com.golden.gamedev.object.sprite.VolatileSprite;

import java.awt.Graphics2D;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.net.*;

// GTGE
import com.golden.gamedev.*;
import com.golden.gamedev.object.*;
import com.golden.gamedev.engine.BaseLoader;

//WISP
import wisp.dataObjects.Statistics;
/**
 *
 * @author Solomon See, Albert Leonard Dizon
 * 
 */
public abstract class CharacterSprite extends AdvanceSprite {
    
    private String name;
    private double targetX, targetY;
  
    private MainGame game;

    public SpriteConstants constant;
    private boolean selected=false;
    private boolean selectable=false;
    
    private ProgressBarSprite hp_bar;
    private ProgressBarSprite mp_bar;
    private String type;
    
    //temporary statistics
    private int currentHP;
    private int maxHP;
    private int currentMP;
    private int maxMP;
    private int attackRate;
    private Actions actions;
    private Statistics statistics;
    
    
    ///for damage display
    private boolean beingDamaged;
    private int damageRecieved;
    private Timer damageTimer;
    private boolean displayDamage;
    private long copyElapsedTime;
    private String damedz;
    
    //for flinch
    private boolean flinch;
    private Timer flinchTimer;
    
    //for buff mode
    private boolean buffed;
    
    //needed to draw SP bar
    private boolean hero;
    
    public void setFlinch(boolean a){
    	flinch = a;
    }
    
    public boolean isFlinch(){
    	return flinch;
    }
    
    
    public long getCopyElapsedTime() {
		return copyElapsedTime;
	}

	public void setCopyElapsedTime(long copyElapsedTime) {
		this.copyElapsedTime = copyElapsedTime;
	}

	public CharacterSprite(String sname, String stype, MainGame game, BufferedImage[] images, double x, double y, boolean h) {
        super(images, x, y + 5);
        name = sname;
        constant = new SpriteConstants();
        this.setGame(game);
        
        actions = new Actions();
        
        setAnimation(constant.STAND, constant.DOWN);
        setLoopAnim(true);
        hp_bar = new ProgressBarSprite(100,100,x,y,getWidth(),3);
        hp_bar.setForeColor(Color.GREEN);
        type = stype;
        
        //TEST TESTING TEMP
        damageTimer = new Timer(1000); //0.2 second damage display time
        beingDamaged = false;
        damageRecieved = 0;
        
        flinchTimer = new Timer(1000);
        flinch = false;
        damedz = new String();
        
        buffed = false;
        
        hero = h;
    }

    public void setMoveLocation(double x, double y) {
        double dispx = (x - getScreenX()) - (getWidth()/2);
        double dispy = (y - getScreenY()) - (getHeight()/2);
        setTargetX(getX() + dispx);
        setTargetY(getY() + dispy);
        
        
        if (Math.abs(dispx) >= Math.abs(dispy)) {
            if (dispx < 0)
                setAnimation(constant.WALKING, constant.LEFT);
            else
                setAnimation(constant.WALKING, constant.RIGHT);
        } else {
            if (dispy < 0)
                setAnimation(constant.WALKING, constant.UP);
            else
                setAnimation(constant.WALKING, constant.DOWN);            
        }
    }
    
    protected boolean move(long elapsedTime) {
        if (getStatus() == constant.WALKING && moveTo(elapsedTime, getTargetX(), getTargetY(), 0.2)) {
            setStatus(constant.STAND);
            return false;
        }
        return true;
    }
    
    public void initStats(int cHP, int mHP, int cMP, int mMP, int atkRate){
    	currentHP = cHP;
    	currentMP = cMP;
    	maxHP = mHP;
    	maxMP = mMP;
    	attackRate = atkRate;
    }
    public double getMiddleX() {
        return getScreenX() + getWidth()/2;
    }
    
    
    public double getMiddleY() {
        return getScreenY() + getHeight()/2;
    }
    
    ///////////////////////////////////////////////////////
    public abstract int[] getUpImages();
    public abstract int[] getDownImages();
    public abstract int[] getLeftImages();
    public abstract int[] getRightImages();
    ///////////////////////////////////////////////////////
    public abstract int[] getUpFlinch();
    public abstract int[] getDownFlinch();
    public abstract int[] getLeftFlinch();
    public abstract int[] getRightFlinch();
    ///////////////////////////////////////////////////////
    // NEW
    ///////////////////////////////////////////////////////
    public abstract int[] getUpBuffed();
    public abstract int[] getDownBuffed();
    public abstract int[] getLeftBuffed();
    public abstract int[] getRightBuffed();
    ///////////////////////////////////////////////////////
    // end NEW
    ///////////////////////////////////////////////////////
    
    protected void animationChanged(int oldStat, int oldDir, int status, int direction) {
        if(flinch)
        {
        	switch(direction) {
        	case 1 : this.setAnimationFrame(getDownFlinch()); break;	//Right
        	case 2 : this.setAnimationFrame(getLeftFlinch()); break;	//Left
        	case 3 : this.setAnimationFrame(getRightFlinch()); break;	//Up
        	case 4 : this.setAnimationFrame(getUpFlinch()); break;		//Down
        	}
        }
        else if(buffed){
        	switch(direction) {
        	case 1 : this.setAnimationFrame(getDownBuffed()); break;	//Right
        	case 2 : this.setAnimationFrame(getLeftBuffed()); break;	//Left
        	case 3 : this.setAnimationFrame(getRightBuffed()); break;	//Up
        	case 4 : this.setAnimationFrame(getUpBuffed()); break;		//Down
        	}
        	if (status == constant.WALKING) {
        		if (!isAnimate())
        			setAnimate(true);
        	} else if (status == constant.STAND) {
        		setAnimate(false);
        	}
        }
        else
        {	switch(direction) {
            	case 1 : this.setAnimationFrame(getDownImages()); break;	//Right
            	case 2 : this.setAnimationFrame(getLeftImages()); break;	//Left
            	case 3 : this.setAnimationFrame(getRightImages()); break;	//Up
            	case 4 : this.setAnimationFrame(getUpImages()); break;		//Down
        	}
        	if (status == constant.WALKING) {
        		if (!isAnimate())
        			setAnimate(true);
        	} else if (status == constant.STAND) {
        		setAnimate(false);
        	}
        }
    }

    public void render(Graphics2D g, int xs, int ys) {
        super.render(g, xs, ys);
        g.setColor(Color.WHITE);
        Font f = g.getFont();
        //
        Font e = new Font("Dialog", Font.BOLD, 18); 
        //
        g.drawString(getName(), xs, ys+getHeight()+ 10);
        if (isSelected()){
            g.drawRect(xs, ys, getWidth(), getHeight() + 10);
            hp_bar.drawBar(g, xs, ys);
            
            if(hero){
            	mp_bar.drawBar(g, xs, ys+3);
            }
        }
        
        //if attacked, display damage indicator
        if(beingDamaged){
        	
        	
        	if(getDamagedRecieved() > 0)
        	{
        		damedz = ((Integer)getDamagedRecieved()).toString();
        	}
        	else if(getDamagedRecieved() == 0)
        		damedz = "MISS";
        	else
        		damedz = " ";
        	
        	g.setFont(e);
        	g.drawString(damedz, xs+(getHeight()/2), ys - 15);
        	g.setFont(f);
        	
        }
        //stop displaying the damage indicator after a preset time
        if (damageTimer.action(copyElapsedTime))
        {
        	beingDamaged = false;
        }
        if(flinchTimer.action(copyElapsedTime))
        {
        	flinch = false;
        }
    }    
	
	public abstract void initObject();
	
	public void selected() {
    }
    
    public void clicked() {
    }
    
    public void deselected() {
    }
    
    public void attack(CharacterSprite target){
    	if(target.getHp_bar().getCurrValue() > 0){
    		target.getHp_bar().setCurrValue(target.getHp_bar().getCurrValue()-1);
    		//System.out.println(this.name + " attacks " + target.name + ":: 1%DMG");
    	}
    }
    
    public abstract void hit(CharacterSprite cs, double damage);
    
    public abstract void resetMode();
    
    public boolean isDead() {
    	if (currentHP <= 0)
    		return true;
    	else
		return false;
	}
    
    
    /**************** GETTERS AND SETTERS ****************/
    
    public int getCurrentHP(){
    	return currentHP;
    }
    
    public void setCurrentHP(int cHP){
    	
    	if (cHP >= maxHP)
    		currentHP = maxHP;
    	else if(cHP < 0)
    	{
    		currentHP = 0;
    	}
    	else	
    	    this.currentHP = cHP;
    }
    
    public int getCurrentMP(){
    	return currentMP;
    }
    
    public void setCurrentMP(int cMP){
    	if(cMP >= maxMP){
    		currentMP = maxMP;
    	}
    	else if( cMP < 0)
    	{
    		currentMP = 0;
    	}
    	else
    		this.currentMP = cMP;
    }
    
    public Actions getActions(){
    	return actions;
    }
    
    public abstract Object getData();
    public void setActions(Actions actions){
    	this.actions = actions;
    }

	public int getMaxHP() {
		return maxHP;
	}

	public void setMaxHP(int maxHP) {
		this.maxHP = maxHP;
	}

	public int getMaxMP() {
		return maxMP;
	}

	public void setMaxMP(int maxMP) {
		this.maxMP = maxMP;
	}
    
	public boolean isBeingDamaged(){
		return beingDamaged;
	}
	
	public void setBeingDamaged(boolean temp){
		beingDamaged = temp;
	}
	
	public int getDamagedRecieved(){
		return damageRecieved;
	}
	
	public void setDamagedRecieved(int temp){
		damageRecieved = temp;
	}
	
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getTargetX() {
        return targetX;
    }

    public void setTargetX(double targetX) {
        if (targetX < 0)
            targetX = 0;
        if (targetX > 2048)
            targetX = 2048 - getWidth();        
        this.targetX = targetX;
    }

    public double getTargetY() {
        return targetY;
    }

    public void setTargetY(double targetY) {
        if (targetY < 0)
            targetY = 0;
        if (targetY > 2048)
            targetY = 2048 - getHeight();                
        this.targetY = targetY;
    }

    public MainGame getGame() {
        return game;
    }

    public void setGame(MainGame game) {
        this.game = game;
    }   
    
    public ProgressBarSprite getHp_bar() {
		return hp_bar;
	}

	public void setHp_bar(ProgressBarSprite hp_bar) {
		this.hp_bar = hp_bar;
	}

	public ProgressBarSprite getMp_bar() {
		return mp_bar;
	}

	public void setMp_bar(ProgressBarSprite mp_bar) {
		this.mp_bar = mp_bar;
	}

	public void hitObstacle(ObstacleSprite obstacle) {
        setStatus(constant.STAND);
    }
    
    public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public Statistics getStatistics(){
		return statistics;
	}
	
	public void setStatistics(Statistics statistics){
		this.statistics = statistics;
	}
	
	public int getAttackRate(){
		return attackRate;
	}
	
	public void setAttackRate(int arate){
		attackRate = arate;
	}
    
    public boolean isSelectable() {
        return selectable;
    }
    
    public void setSelectable(boolean selectable) {
        this.selectable = selectable;
    }
    
    public boolean isSelected() {
        return selected;
    }
    public void setSelected(boolean selected) {
        this.selected = selected;
        if (selected)
            selected();
        else
            deselected();
    }
    
    public boolean isDisplayingDamage(){
    	return displayDamage;
    }
    
    public void setDisplayDamage(boolean temp){
    	displayDamage = temp;
    }
    
    public boolean isBuffed(){
    	return buffed;
    }
    
    public void setBuffed(boolean bufflolz){
    	this.buffed = bufflolz;
    }
}
